import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:sliding_motion/ly_sliding_controller.dart';
import 'ly_app_color.dart';
import 'ly_arc_painter.dart';

class LYSlidingMotionControl extends StatefulWidget {
  final Function()? onDragStart;
  final Function()? onDragEnd;
  final double boundsSize;
  final double padSize;
  final Function(double dx, double dy)? onDragUpdate;
  final Widget? leftWidget;
  final Widget? rightWidget;
  final Widget? topWidget;
  final Widget? bottomWidget;
  final Widget? padWidget;
  final double maxValue;
  final double minValue;
  final bool enable;
  final Color slidingColor;
  final bool slidingVisible;

  const LYSlidingMotionControl(
      {super.key,
      this.onDragUpdate,
      this.onDragStart,
      this.onDragEnd,
      this.boundsSize = 160,
      this.padSize = 55,
      this.bottomWidget,
      this.topWidget,
      this.leftWidget,
      this.rightWidget,
      this.padWidget,
      this.maxValue = 1,
      this.minValue = 0,
      this.enable = true,
      this.slidingVisible = true,
      this.slidingColor = const Color(0xff00ff00)})
      : assert(maxValue > minValue && minValue >= 0, 'minValue必须大于或等于0，maxValue值必须大于minValue');

  @override
  State<LYSlidingMotionControl> createState() => _LYSlidingMotionControlState();
}

class _LYSlidingMotionControlState extends State<LYSlidingMotionControl> {
  LYSlidingController controller = LYSlidingController();
  late double limit;
  final double _space = 10;
  bool isNeedCalculate = false;
  late double deltaValue;
  late double r;
  late Widget padWidget;
  // late Widget leftWidget;
  // late Widget rightWidget;
  // late Widget topWidget;
  // late Widget bottomWidget;
  @override
  void initState() {
    super.initState();
    initWidget();
    controller.slidingVisible = widget.slidingVisible;
    r = widget.boundsSize * 0.5;
    limit = (widget.boundsSize - widget.padSize) * 0.5;
    isNeedCalculate = widget.maxValue != 1 || widget.maxValue != 0;
    deltaValue = widget.maxValue - widget.minValue;
  }

  void initWidget() {
    padWidget = widget.padWidget ??
        Container(
          width: widget.padSize,
          height: widget.padSize,
          decoration: BoxDecoration(
              color: AppColor.whiteColor,
              borderRadius: BorderRadius.circular(widget.padSize * 0.5)),
        );
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      width: widget.boundsSize,
      height: widget.boundsSize,
      alignment: Alignment.center,
      decoration: BoxDecoration(
        color: const Color(0x4D787878),
        borderRadius: BorderRadius.circular(r),
      ),
      child: Stack(
        fit: StackFit.expand,
        alignment: Alignment.center,
        children: [
          if (widget.slidingVisible)
            ListenableBuilder(
                listenable: controller,
                builder: (ctx, child) {
                  return LYArcPainterContainer(
                    point: controller.intersectionPoint,
                    radius: widget.boundsSize * 0.5,
                    color: widget.slidingColor,
                  );
                }),
          ListenableBuilder(
              listenable: controller,
              builder: (ctx, child) {
                return Transform.translate(
                  offset: controller.position,
                  child: child,
                );
              },
              child: GestureDetector(
                onPanStart: _onPanStart,
                onPanUpdate: _onPanUpdate,
                onPanEnd: _onPanEnd,
                child: Center(child: padWidget),
              )),
          Positioned(
            left: _space,
            child: widget.leftWidget ??
                const Icon(
                  Icons.arrow_back_ios,
                  size: 15,
                  weight: 900,
                ),
          ),
          Positioned(
              right: _space,
              child: widget.rightWidget ??
                  const Icon(
                    Icons.arrow_forward_ios_rounded,
                    size: 15,
                  )),
          Positioned(
            top: _space,
            child: widget.topWidget ?? const Icon(Icons.keyboard_arrow_up_sharp),
          ),
          Positioned(
            bottom: _space,
            child: widget.bottomWidget ?? const Icon(Icons.keyboard_arrow_down_sharp),
          ),
        ],
      ),
    );
  }

  void _onPanUpdate(DragUpdateDetails details) {
    if (widget.enable) {
      final intervalOffset = details.localPosition - controller.startMoveOffset;
      if (widget.slidingVisible) {
        _updateArc(intervalOffset.dx, intervalOffset.dy);
      }
      controller.position = _findIntersection(intervalOffset.dx, intervalOffset.dy);
      if (!controller.position.isFinite) {
        controller.position = Offset.zero;
      }
      final scaleX = controller.position.dx / limit;
      final scaleY = -(controller.position.dy / limit);
      if (!isNeedCalculate) {
        widget.onDragUpdate?.call(scaleX, scaleY);
        return;
      }
      final ys = scaleY < 0 ? -1 : 1;
      final xs = scaleX < 0 ? -1 : 1;
      final y = (deltaValue * scaleY.abs() + widget.minValue) * ys;
      final x = (deltaValue * scaleX.abs() + widget.minValue) * xs;
      // debugPrint("scaleX:$scaleX-scaleY:$scaleY-y=$y-x=$x");
      widget.onDragUpdate?.call(x, y);
    }
  }

  void _onPanStart(DragStartDetails details) {
    controller.intersectionPoint = Offset.zero;
    controller.startMoveOffset = details.localPosition;
    widget.onDragStart?.call();
  }

  void _onPanEnd(DragEndDetails? details) {
    controller.position = Offset.zero;
    controller.intersectionPoint = Offset.zero;
    widget.onDragEnd?.call();
  }

  Offset _findIntersection(double x, double y) {
    final distance = sqrt(pow(x, 2) + pow(y, 2));
    if (distance < limit) {
      return Offset(x, y);
    }
    if (x == 0) {
      return Offset.zero;
    }
    final k = y / x;
    double dx = sqrt(pow(limit, 2) / (pow(k, 2) + 1));
    if (x < 0) {
      dx = -dx;
    }
    double dy = k * dx;
    return Offset(dx, dy);
  }

  void _updateArc(double x, double y) {
    if (x == 0) {
      return;
    }
    final k = y / x;
    double dx = sqrt(pow(r, 2) / (pow(k, 2) + 1));
    if (x < 0) {
      dx = -dx;
    }
    double dy = k * dx;
    controller.intersectionPoint = Offset(dx + r, dy + r);
  }
}
